home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / Common / ZStackCrawl.cpp < prev    next >
Text File  |  1997-06-21  |  9KB  |  334 lines

  1. /*
  2.  *  File:       ZStackCrawl.h
  3.  *  Summary:       Stack crawl class based on the class in the OpenDoc utilities.
  4.  *  Written by: Jesse Jones
  5.  *
  6.  *  Copyright ゥ 1997 Jesse Jones. 
  7.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  8.  *
  9.  *  Change History (most recent first):    
  10.  *
  11.  *         <5>     5/24/97    JDJ        Turned on scheduling.
  12.  *         <4>     3/28/97    JDJ        Ctor stops crawling if get a bogus nextStackFrame.
  13.  *         <3>     2/28/97    JDJ        Added a bulleted comment to GetMem.
  14.  *         <2>     2/27/97    JDJ        Removed PPCToolLibs stubs.
  15.  *         <1>     2/02/97    JDJ        Created.
  16.  */
  17.  
  18. #include <ZStackCrawl.h>
  19.  
  20. #include <Errors.h>
  21. #include <Files.h>
  22. #include <LowMem.h>
  23. #include <Setjmp.h>
  24. #include <Stdio.h>
  25. #include <Unmangler.h>
  26.  
  27. #include <ZDebug.h>
  28. #include <ZNubEmbeddedSymbols.h>
  29.  
  30.  
  31. #pragma peephole            on
  32. #pragma global_optimizer     on
  33. #pragma auto_inline            on
  34. #pragma  scheduling          603
  35.  
  36. #if powerc
  37. #pragma optimization_level    4
  38. #endif
  39.  
  40. //==============================================================================
  41. // Stack-crawl types & constants
  42. //==============================================================================
  43. struct LinkAreaPPC {
  44.     void*    backChain;
  45.     void*    savedCR;
  46.     void*    savedLR;
  47.     void*    reserved;
  48.     void*    savedTOC;
  49. };
  50.  
  51. struct LinkArea68k {
  52.     void*    backChain;
  53.     void*    returnAddress;
  54. };
  55.  
  56. union LinkArea {
  57.     LinkAreaPPC fPPC;
  58.     LinkArea68k f68k;
  59. };
  60.  
  61. const size_t kMagicA6 = 0xFFFFFFFF;                // Signals 68k->PPC switch
  62. const size_t kPPCInstrLen = 4;                    // Gotta love them RISCs
  63.  
  64.  
  65. //==============================================================================
  66. // Locating Stack Pointer
  67. //==============================================================================
  68. #if GENERATING68K
  69.     #pragma parameter __D0 GetA6()
  70.     extern void* GetA6() = 0x200E;          // MOVE.L A6,D0
  71. #elif GENERATINGPOWERPC
  72.     #ifdef __MWERKS__
  73.         #if __MWERKS__ >= 8
  74.             asm static void* GetSP( ) {
  75.                 mr r3,SP
  76.                 blr
  77.             }
  78.         #else
  79.             const long kjmp_bufStackFrameIndex = 3;        // For CW8 and earlier, not CW9
  80.         #endif
  81.     #elif defined(__MRC__)
  82.         const long kjmp_bufStackFrameIndex = 2;            // For MRC
  83.     #else
  84.         #error "Don't know offset of SP in jmp_buf for this compiler"
  85.     #endif
  86. #else
  87.     #error "What the hell kinda CPU is this?"
  88. #endif
  89.  
  90.  
  91. // ===================================================================================
  92. //    class StackID
  93. //        This is just a cookie: it's only used to provide some type safety in the interface.
  94. // ===================================================================================
  95. class StackID {
  96. };
  97.  
  98.  
  99. // ===================================================================================
  100. //    Internal Functions
  101. // ===================================================================================
  102.  
  103. //---------------------------------------------------------------
  104. //
  105. // GetMem
  106. //
  107. //---------------------------------------------------------------
  108. static OSErr GetMem(void* loc, ULongWord size, void* buffer, va_list args )
  109. {
  110.     #pragma unused(args)
  111.     
  112.     // Try to get away without a CPU exception handler by sanity checking:
  113.     // ・・・ハThis test does not work when virtual memory is on (which
  114.     // ・・・ハmeans the stack crawl has hex addresses instead of names).
  115.     if (loc < &SystemZone()->heapData || (void*) loc > LMGetBufPtr()
  116.                                       || (void*) ((size_t) loc+size) > LMGetBufPtr())
  117.         return -1;
  118.         
  119.     else {
  120.         BlockMoveData(loc, buffer, size);
  121.         return noErr;
  122.     }
  123. }
  124.  
  125. #pragma mark -
  126.  
  127. // ===================================================================================
  128. //    class TStackCrawl
  129. // ===================================================================================
  130.  
  131. //---------------------------------------------------------------
  132. //
  133. // TStackCrawl::~TStackCrawl
  134. //
  135. //---------------------------------------------------------------
  136. TStackCrawl::~TStackCrawl()
  137. {
  138. }
  139.  
  140.  
  141. //---------------------------------------------------------------
  142. //
  143. // TStackCrawl::TStackCrawl
  144. //
  145. //---------------------------------------------------------------
  146. TStackCrawl::TStackCrawl(ulong startFrame, ulong numFrames)
  147. {
  148.     ASSERT(startFrame < 16*1024L*1024L);
  149.     ASSERT(numFrames > 0);
  150.     
  151.     if (numFrames > kMaxFrames)
  152.         numFrames = kMaxFrames;
  153.     
  154.     const void* stackTop;
  155.     
  156.     // Skanky ways to read the CPU registers:
  157. #if GENERATING68K
  158.     stackTop = GetA6();
  159. #elif GENERATINGPOWERPC
  160.     #if defined(__MWERKS__) && __MWERKS__ >= 8
  161.         stackTop = GetSP();
  162.     #else
  163.     {
  164.         jmp_buf regs;
  165.         (void) setjmp(regs);
  166.         stackTop = regs[kjmp_bufStackFrameIndex];
  167.     }
  168.     #endif
  169. #endif
  170.     
  171.     const LinkArea* stackFrame = (LinkArea*) stackTop;
  172.     const LinkArea* lastStackFrame = nil;
  173.     bool isNative = GENERATINGPOWERPC;
  174.     const void* pc = nil;
  175.     
  176.     // Crawl up the stack:
  177.     ulong nFrames = 0;
  178.     ulong endAt = startFrame + numFrames - 1;
  179.     while (stackFrame != nil && stackFrame > lastStackFrame && nFrames <= endAt) {
  180.         const LinkArea *nextStackFrame;
  181.         
  182. #if GENERATINGPOWERPC
  183.         if (!isNative) {
  184.             nextStackFrame = (LinkArea*) stackFrame->f68k.backChain;
  185.             if ((char*) nextStackFrame >= LMGetCurStackBase())
  186.                 break;
  187.             else if (((size_t*) nextStackFrame)[-1] == kMagicA6)    {        // 68k->PPC switch
  188.                 isNative = true;
  189.                 stackFrame = nextStackFrame;                        // Skip switch frame
  190.             } else
  191.                 pc = stackFrame->f68k.returnAddress;
  192.         }
  193.  
  194.         if (isNative) {
  195.             nextStackFrame = (const LinkArea*) stackFrame->fPPC.backChain;
  196.             if ((char*) nextStackFrame >= LMGetCurStackBase())
  197.                 break;
  198.             else if ((ulong) nextStackFrame & 1) {                        // PPC->68k switch
  199.                 nextStackFrame = (LinkArea*) ((size_t)nextStackFrame -1);
  200.                 isNative = false;
  201.                 pc = nextStackFrame->f68k.returnAddress;
  202.                 nextStackFrame = (const LinkArea*) nextStackFrame->f68k.backChain;
  203.             } else {
  204.                 pc = (void*) ((size_t) nextStackFrame->fPPC.savedLR - kPPCInstrLen);
  205.             }
  206.         }
  207. #else
  208.         nextStackFrame = (LinkArea*) stackFrame->f68k.backChain;
  209.         pc = stackFrame->f68k.returnAddress;
  210. #endif
  211.  
  212.         // If we've reached startFrame record the PC value in our list.
  213.         if (nFrames >= startFrame)
  214.             mFrame[nFrames - startFrame] = (const void*) ((size_t) pc | isNative);
  215.  
  216.         // Advance to next frame:
  217.         lastStackFrame = stackFrame;
  218.         stackFrame = (LinkArea*) nextStackFrame;
  219.         nFrames++;
  220.         
  221.         // Stop if we've hit the base of the stack:
  222.         size_t postFrame = (size_t)stackFrame + (isNative ? sizeof(LinkAreaPPC)
  223.                                                           : sizeof(LinkArea68k));
  224.         if (postFrame >= (size_t) LMGetCurStackBase())
  225.             break;
  226.     }
  227.     
  228.     if (nFrames > startFrame)
  229.         mNumFrames = nFrames - startFrame;
  230.     else
  231.         mNumFrames = 0;                        // can happen if allocate blocks within DumpLeaks
  232. }
  233.  
  234.  
  235. //---------------------------------------------------------------
  236. //
  237. // TStackCrawl::GetFrame (ulong)
  238. //
  239. //---------------------------------------------------------------
  240. SStackFrame TStackCrawl::GetFrame(ulong index) const
  241. {
  242.     ASSERT(index < 16*1024L*1024L);
  243.     ASSERT(index < mNumFrames);
  244.     
  245.     size_t pc   = (size_t) mFrame[index] & ~1;
  246.     bool native = (bool) ((size_t) mFrame[index] & 1);
  247.     
  248.     return TStackCrawl::GetFrame(pc, native);
  249. }
  250.  
  251.  
  252. //---------------------------------------------------------------
  253. //
  254. // TStackCrawl::GetID
  255. //
  256. //---------------------------------------------------------------
  257. StackFrameID TStackCrawl::GetID(ulong index) const
  258. {
  259.     ASSERT(index < 16*1024L*1024L);
  260.     ASSERT(index < mNumFrames);
  261.         
  262.     StackFrameID id = (StackFrameID) mFrame[index];
  263.     
  264.     return id;
  265. }
  266.  
  267.  
  268. //---------------------------------------------------------------
  269. //
  270. // TStackCrawl::GetFrame (StackFrameID)                    [static]
  271. //
  272. //---------------------------------------------------------------
  273. SStackFrame TStackCrawl::GetFrame(StackFrameID id)
  274. {
  275.     ASSERT(id != nil);
  276.     
  277.     size_t pc   = (size_t) id & ~1;
  278.     bool native = (bool) ((size_t) id & 1);
  279.     
  280.     return TStackCrawl::GetFrame(pc, native);
  281. }
  282.  
  283.  
  284. //---------------------------------------------------------------
  285. //
  286. // TStackCrawl::GetCaller                                [static]
  287. //
  288. //---------------------------------------------------------------
  289. SStackFrame TStackCrawl::GetCaller()
  290. {
  291.     TStackCrawl crawl(2, 1);
  292.     
  293.     return crawl.GetFrame(0);
  294. }
  295.  
  296.  
  297. //---------------------------------------------------------------
  298. //
  299. // TStackCrawl::GetFrame (size_t, bool)                    [static]
  300. //
  301. //---------------------------------------------------------------
  302. SStackFrame TStackCrawl::GetFrame(size_t pc, bool native)
  303. {
  304.     size_t begin, end;
  305.     
  306.     OSErr err;
  307.     char symbol[256];
  308.     if (native)
  309. #if GENERATINGPOWERPC
  310.         err = LookupPowerPCSym(pc, symbol, &begin, &end, &GetMem);
  311. #else
  312.         err = 12345;
  313. #endif
  314.     else
  315.         err = Lookup68KSym(pc, symbol, &begin, &end, &GetMem);
  316.         
  317.     char fnName[256];
  318.     if (err == noErr && symbol[0] != 0)
  319.         unmangle(fnName, &symbol[1+(symbol[1] == '.')], 255);    // For some reason the traceback names seem to start with "."
  320.     else
  321.         sprintf(fnName,"%08p (%s)", pc, native ? "PPC" : "68k");
  322.  
  323.     SStackFrame frame;
  324.     
  325.     frame.name   = fnName;
  326.     frame.start  = (const void*) begin;
  327.     frame.offset = pc - begin;
  328.     frame.native = native;
  329.     
  330.     return frame;
  331. }
  332.  
  333.  
  334.